<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
    <style type="text/css">
        body{
            background: rgba(100, 145, 250, .3);
        }

        #scaleSlider{
            vertical-align: 10px;
            width:100px;
            margin-left: 90px;
        }

        #canvas{
            margin: 10px 20px 0 20px;
            border: thin solid #aaa;
            cursor: crosshair;
        }

        #controls{
            margin-left: 15px;
            padding:0;
        }

        #scaleOutput{
            position: absolute;
            width: 60px;
            height: 30px;
            margin-left: 10px;
            vertical-align: center;
            text-align: center;
            color:blue;
            font:18px Arial;
            text-shadow:2px 2px 4px rgba(100, 140, 250, .8);
        }
    </style>
</head>
<body>
    <div id="controls">
        <output id="scaleOutput">1.0</output>
        <input id="scaleSlider" type="range" min="1" max="3.0" step=".01" value="1.0">
    </div>
    <canvas id="canvas" width=600 height=400>
        Canvas not supported
    </canvas>

    <script type="text/javascript">

    var canvas = document.getElementById("canvas"),
        context = canvas.getContext("2d"),

        image = new Image(),
        scaleSlider = document.getElementById("scaleSlider"),
        scale=1.0,
        MINIMUM_SCALE = 1.0,
        MAXIMUM_SCALE = 3.0;

    function drawImage(){
        var w = canvas.width,
            h = canvas.height,
            sw = w*scale,
            sh = h*scale;

        context.save();
        context.clearRect(0, 0, canvas.width, canvas.height);
        context.drawImage(image, -sw/2+w/2, -sh/2+h/2, sw, sh);
        context.drawImage(image, w, 0);
        context.restore();
    }

    function drawScaleText(value){
        var text = parseFloat(value).toFixed(2);
        var percent = parseFloat(value - MINIMUM_SCALE) / parseFloat(MAXIMUM_SCALE - MINIMUM_SCALE);
        scaleOutput.innerText = text;
        percent = percent < 0.35 ? 0.35 : percent;
        scaleOutput.style.fontSize = percent*MAXIMUM_SCALE/1.5 + "em";
    }

    scaleSlider.onchange = function(e){
        scale = e.target.value;
        if(scale<MINIMUM_SCALE) scale = MINIMUM_SCALE;
        else if (scale > MAXIMUM_SCALE) scale = MAXIMUM_SCALE;

        drawScaleText(scale);
        drawImage();
    }

    function windowToCanvas(e){
        var bbox = canvas.getBoundingClientRect();
        return {
            x:e.clientX - bbox.left*(canvas.width/bbox.width),
            y:e.clientY - bbox.top*(canvas.height/bbox.height)
        }
    }

    lastP = null;
    canvas.onmousemove = function(e){
        e.preventDefault();
        p = windowToCanvas(e);
        if(lastP){
            lastP = p;
            x = p.x - lastP.x;
            y = p.y - lastP.y;
            context.save();
            context.clearRect(0, 0, canvas.width, canvas.height);
            context.drawImage(image, 0, 0);
            context.drawImage(image, image.width, 0);
            context.translate(x, 0);
            context.restore();
        }else{
            lastP = p;           
        }
    }

    context.fillStyle = "cornflowerblue";
    context.strokeStyle = "yellow";
    context.shadowColor = "rgba(50, 50, 50, 1.0)";
    context.shadowOffsetX = 5;
    context.shadowOffsetY = 5;
    context.shadowBlur = 10;

    image.src = "waterfall.jpg";
    image.onload = function(e){
        drawImage();
        drawScaleText(scaleSlider.value);
    }

    </script>
</body>
</html>